/**
 *
 */
package cn.xuqiudong.elasticsearch.helper;

import cn.xuqiudong.elasticsearch.autoconfigure.IndexConfig;
import cn.xuqiudong.elasticsearch.autoconfigure.IndexConfig.IndexProperty;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.admin.indices.alias.Alias;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.rest.RestStatus;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.*;

/**
 * 说明 :  关于ES 的Index的工具类
 * @author Vic.xu
 * @since  2020年9月10日下午7:51:43
 */

public class IndexHelper {

    private RestHighLevelClient restHighLevelClient;

    public IndexHelper() {

    }

    public IndexHelper(RestHighLevelClient restHighLevelClient) {
        this.restHighLevelClient = restHighLevelClient;
    }

    /**
     * 删除索引
     *
     * @param index
     * @return
     * @throws IOException
     */
    public boolean deleteIndex(String index) throws IOException {
        try {
            DeleteIndexRequest request = new DeleteIndexRequest(index);
            AcknowledgedResponse response = restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);

            return response.isAcknowledged();
        } catch (ElasticsearchException exception) {
            if (exception.status() == RestStatus.NOT_FOUND) {
                // throw new commonrun("Not found index: " + index);
            }
            throw exception;
        }
    }

    /**
     * 判断索引是否 存在
     *
     * @param index 索引名称
     * @return
     * @throws IOException
     */
    public boolean isExistIndex(String index) throws IOException {
        GetIndexRequest getIndexRequest = new GetIndexRequest(index);
        getIndexRequest.local(false);
        getIndexRequest.humanReadable(true);
        getIndexRequest.includeDefaults(false);
        return restHighLevelClient.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
    }

    /**
     * 创建索引
     *
     * @param index      索引名称
     * @param properties mappings中的属性
     * @return
     * @throws IOException
     */
    public boolean createIndex(IndexConfig config) throws IOException {
        XContentBuilder builder = XContentFactory.jsonBuilder();
        builder.startObject().startObject("mappings")
                .field("properties", buildIndexProperties(config.getProperties())).endObject()
                .startObject("settings").field("number_of_shards", config.getShards())
                .field("number_of_replicas", config.getReplicas())
                // 设置默认的分词器
                .field("index.analysis.analyzer.default.type", config.getAnalyzer()).endObject().endObject();
        CreateIndexRequest request = new CreateIndexRequest(config.getName()).source(builder);

        //别名
        String alias = StringUtils.isEmpty(config.getAlias()) ? config.getName() + "_alias" : config.getAlias();
        request.alias(new Alias(alias));
        CreateIndexResponse response = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);
        boolean acknowledged = response.isAcknowledged();
        Assert.isTrue(acknowledged, "创建Index[" + config.getName() + "]失败");
        return acknowledged;
    }

    /**
     * 构建索引的配置属性
     * @param list  IndexProperty 集合
     * @return mapping
     */
    public static Map<String, Map<String, Object>> buildIndexProperties(List<IndexProperty> list) {
        Map<String, Map<String, Object>> properties = new HashMap<>();

        // 加一个默认的 ： id 主要用来排序 因为它是自增的 还有关联mysql的数据 如果配置了 会覆盖此默认配置
        putSubProperties(properties, "id", "keyword");

        Optional.ofNullable(list).orElse(new ArrayList<IndexProperty>())
                .forEach(p -> putSubProperties(properties, p.getField(), p.getType()));

        return properties;
    }

    /**
     * 查询子字段配置
     *
     * @param properties
     * @param field      字段名
     * @param type       text类型
     * @return
     */
    public static Map<String, Object> putSubProperties(Map<String, Map<String, Object>> properties, String field,
                                                       String type) {
        Map<String, Object> subProperties = new HashMap<>();
        subProperties.put("type", type);
        properties.put(field, subProperties);
        return subProperties;
    }

}
